package com.bawei.reflection;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 三个重要方法：
 * getGenericType():获得完整的数据类型，包括范型，是Field的方法
 * getRawType():获得原始数据类型，不包括范性，是Field的方法
 * getActualTypeArguments():获得参数化类型里的范性，是ParameterizedType里方法
 *
 *
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "ytx";

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //参数化类型练习
        Class clazz = ReflectTestBean.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Log.d(TAG, "getGenericType获得完整数据类型: "+declaredField.getGenericType());
            Log.d(TAG, ""+declaredField.getName()+"是否为参数化类型"+(declaredField.getGenericType() instanceof ParameterizedType));
        }
//        getGenericType获得完整数据类型: java.util.List<java.lang.String>
//        list1是否为参数化类型true
//        getGenericType获得完整数据类型: interface java.util.List
//        list2是否为参数化类型false
//        getGenericType获得完整数据类型: java.util.Map<java.lang.String, java.lang.Integer>
//        map1是否为参数化类型true
//        getGenericType获得完整数据类型: interface java.util.Map map2是否为参数化类型false
        //获得参数化类型里面的范型
        for (Field declaredField : declaredFields) {
            //判断该属性是不是参数化类型
            if(declaredField.getGenericType() instanceof ParameterizedType){
                //获得完整数据类型，并强转成ParameterizedType
                ParameterizedType parameterizedType = (ParameterizedType) declaredField.getGenericType();
              //  Log.d(TAG, declaredField.getName() + " 的属性为：" + parameterizedType.getTypeName());
                //通过参数化类型获得里面的范型
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type type : actualTypeArguments) {
                    Log.d(TAG, "真实的泛型的类型为：" + type.getTypeName());
                }

            }
        }
        //获得原始数据类型
        for (Field field : declaredFields) {
            // 先判断字段是否带有泛型
            if (field.getGenericType() instanceof ParameterizedType) {
                ParameterizedType type = (ParameterizedType) field.getGenericType();
                Log.d(TAG,field.getName() + " 的字段类型为：" + type.getRawType().getTypeName());
            }
        }


    }

    //反射基础练习
    public void testOne(){
        try {
            //1。获得class对象：三种方式
            Class clazz1 = Student.class;
            Class clazz2 = Class.forName("com.bawei.reflection.Student");
            Student student = new Student();
            Class clazz3 = student.getClass();
            Log.d(TAG, "main: "+(clazz1 == clazz2));
            Log.d(TAG, "main: "+(clazz2 == clazz3));
            //2:获得名称
            Log.d(TAG, "包名: "+clazz1.getPackage().getName());
            Log.d(TAG, "类名: "+clazz1.getSimpleName());
            Log.d(TAG, "完整类名: "+clazz1.getName());
            //3:获得属性
            Field[] fields = clazz1.getFields();//只能获得本类以及父类public属性
            Field[] declaredFields = clazz1.getDeclaredFields();//只能获得本类全部属性，包括私有的
            Field tall = clazz1.getField("tall");
            Field talls = clazz1.getDeclaredField("tall");
            //4；获得构造方法
            Constructor[] constructors = clazz1.getConstructors();//获得所有public构造
            Constructor[] declaredConstructors = clazz1.getDeclaredConstructors();//获得所有的构造，包括私有的
            Constructor constructor = clazz1.getConstructor(String.class);
            //5:获得方法
            Method[] methods = clazz1.getMethods();//获得父类以及本类中所有的public方法
            Method[] declaredMethods = clazz1.getDeclaredMethods();//获得本类中所有方法，包括私有的,不包括父类的
            try {
                Method method2 = clazz1.getMethod("method2", String.class);
                Method method1 = clazz1.getDeclaredMethod("method1");
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            /**********************************/
            //6：使用反射创建对象
            Student student1 = (Student) clazz1.newInstance();//直接用class创建对象,只能无参
            Constructor declaredConstructor = clazz1.getDeclaredConstructor(String.class, int.class);
            declaredConstructor.setAccessible(true);//允许访问
            Student student2 = (Student) declaredConstructor.newInstance("占三", 34);//用构造创建对象
            //7：使用反射设置属性 获得属性
            Field username = clazz1.getDeclaredField("username");
            username.setAccessible(true);
            username.set(student2,"张三");//为student2对象设置username属性
            String  name = (String) username.get(student2);//获得student2的username属性
            Log.d(TAG, "修改玩的属性: "+name);
            //8：使用反射调用某个对象的方法
            Method declaredMethod = clazz1.getDeclaredMethod("method2", String.class);
            String  info = (String) declaredMethod.invoke(student2, "八维");
            Log.d(TAG, "调用方法: "+info);
            /*************参数化类型*********************/





        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}